use crate::GITCODE_API_URL as Host;
use crate::{CLIENT, HEADERS};
use anyhow::Context;
use serde::Deserialize;
use serde_json::json;

macro_rules! parse_json {
    ($text:expr, $type:ty) => {
        serde_json::from_str::<$type>($text)
            .map_err(|e| anyhow::anyhow!("响应解析失败: {}\n原始响应: {}", e, $text))
    };
}

#[derive(Debug, Deserialize)]
pub struct ApiError {
    pub error_code: u32,
    pub error_code_name: String,
    pub error_message: String,
    pub trace_id: String,
}

#[derive(Debug, Deserialize)]
pub struct Author {
    pub id: String,
    pub login: String,
    pub name: String,
    pub avatar_url: String,
    pub html_url: String,
    #[serde(rename = "type")]
    pub type_: String,
    pub url: String,
}

#[derive(Debug, Deserialize)]
pub struct Asset {
    pub browser_download_url: String,
    pub name: String,
    #[serde(rename = "type")]
    pub type_: String,
}

#[derive(Debug, Deserialize)]
pub struct ReleaseResponse {
    pub tag_name: String,
    pub target_commitish: String,
    pub prerelease: bool,
    pub name: String,
    pub body: String,
    pub author: Author,
    pub created_at: String,
    pub assets: Vec<Asset>,
}

#[derive(Debug, Deserialize)]
pub struct UploadUrlResponse {
    pub url: String,
    pub headers: UploadHeaders,
}

#[derive(Debug, Deserialize)]
pub struct UploadHeaders {
    #[serde(rename = "x-obs-meta-project-id")]
    pub x_obs_meta_project_id: String,
    #[serde(rename = "x-obs-acl")]
    pub x_obs_acl: String,
    #[serde(rename = "x-obs-callback")]
    pub x_obs_callback: String,
    #[serde(rename = "Content-Type")]
    pub content_type: String,
}

/// 创建仓库Release
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `tag_name`: 要创建的Release的Git标签名称
/// - `name`: Release的标题名称
/// - `body`: Release的详细描述(Markdown格式)
/// - `target`: 指定基于哪个commit创建Release，可以是分支名、tag或commit hash
///
/// # 返回值
/// 成功时返回创建的Release信息，失败时返回错误
pub async fn create_release(
    or: &str,
    tag_name: &str,
    name: &str,
    body: &str,
    target: Option<&str>,
) -> anyhow::Result<Result<ReleaseResponse, ApiError>> {
    let url = format!("{}/repos/{}/releases", Host, or);
    let request_body =
        json!({"tag_name": tag_name, "name": name, "body": body, "target_commitish": target,});

    let response = CLIENT
        .post(&url)
        .headers({
            let mut headers = HEADERS.clone(); // 新建HeaderMap
            headers.insert(
                reqwest::header::CONTENT_TYPE,
                "application/json".parse().unwrap(),
            );
            headers.insert(reqwest::header::ACCEPT, "application/json".parse().unwrap());
            headers
        })
        .json(&request_body)
        .send()
        .await
        .context("Failed to send request to GitCode API")?;

    // 先获取响应文本
    let response_text = response
        .text()
        .await
        .context("Failed to get response text")?;

    parse_response(response_text)
}

/// 更新指定标签的仓库Release
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `tag`: 要更新的Release的Git标签名称
/// - `name`: 新的Release标题名称
/// - `body`: 新的Release详细描述(Markdown格式)
///
/// # 返回值
/// 成功时返回更新后的Release信息，失败时返回错误
pub async fn update_release(
    or: &str,
    tag: &str,
    name: &str,
    body: &str,
) -> anyhow::Result<Result<ReleaseResponse, ApiError>> {
    let url = format!("{}/repos/{}/releases/{}", Host, or, tag);
    let request_body = json!({ "name": name, "body": body });

    let response = CLIENT
        .patch(&url)
        .headers({
            let mut headers = HEADERS.clone(); // 新建HeaderMap
            headers.insert(
                reqwest::header::CONTENT_TYPE,
                "application/json".parse().unwrap(),
            );
            headers.insert(reqwest::header::ACCEPT, "application/json".parse().unwrap());
            headers
        })
        .json(&request_body)
        .send()
        .await
        .context("Failed to send request to GitCode API")?;

    // 先获取响应文本
    let response_text = response
        .text()
        .await
        .context("Failed to get response text")?;

    parse_response(response_text)
}

/// 获取Release附件上传地址
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `tag`: Release的Git标签名称
/// - `file_name`: 要上传的文件名称
///
/// # 返回值
/// 成功时返回上传URL，失败时返回错误
pub async fn fetch_upload_url(
    or: &str,
    tag: &str,
    file_name: &str,
) -> anyhow::Result<Result<UploadUrlResponse, ApiError>> {
    let url = format!(
        "{}/repos/{}/releases/{}/upload_url?file_name={}",
        Host, or, tag, file_name
    );

    let mut headers = HEADERS.clone();
    headers.insert("Accept", "application/json".parse()?);

    let request = CLIENT.request(reqwest::Method::GET, url).headers(headers);
    let response = request.send().await?;
    let body = response.text().await?;

    parse_json!(&body, UploadUrlResponse)
        .map(Ok)
        .or_else(|_| parse_json!(&body, ApiError).map(Err))
}

/// 获取仓库的单个Release信息
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `tag`: Release的Git标签名称
///
/// # 返回值
/// 成功时返回Release详细信息，失败时返回错误
pub fn fetch_release(or: &str, tag: &str) {
    let url = format!("{}/repos/{}/releases/{}", Host, or, tag);
    // ...
}

/// 获取仓库最后更新的Release信息
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
///
/// # 返回值
/// 成功时返回最新的Release信息，失败时返回错误
pub fn fetch_latest_release(or: &str) {
    let url = format!("{}/repos/{}/releases/latest", Host, or);
    // ...
}

/// 根据Tag名称获取仓库的Release信息
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `tag`: 要查询的Git标签名称
///
/// # 返回值
/// 成功时返回指定标签的Release信息，失败时返回错误
pub fn fetch_release_by_tag(or: &str, tag: &str) {
    let url = format!("{}/repos/{}/releases/tags/{}", Host, or, tag);
    // ...
}

/// 获取仓库的所有Releases列表
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `direction`: 可选，排序方向("asc"升序/"desc"降序)，默认升序
/// - `page`: 可选，当前页码，从1开始
/// - `per_page`: 可选，每页数量(1-100)，默认20
///
/// # 返回值
/// 成功时返回Release列表，失败时返回错误
pub fn fetch_all_releases(
    or: &str,
    direction: Option<&str>,
    page: Option<usize>,
    per_page: Option<usize>,
) {
    let mut url = format!("{}/repos/{}/releases", Host, or);
    // 构建查询参数
    let mut query_params = vec![];

    if let Some(dir) = direction {
        query_params.push(format!("direction={}", dir));
    }

    if let Some(p) = page {
        query_params.push(format!("page={}", p));
    }

    if let Some(pp) = per_page {
        query_params.push(format!("per_page={}", pp.min(100))); // 限制最大100
    }

    if !query_params.is_empty() {
        url.push('?');
        url.push_str(&query_params.join("&"));
    }
    // ...
}

/// 下载仓库Release附件
///
/// # 参数
/// - `or`: 仓库路径，格式为 `owner/repo`
/// - `tag`: Release的Git标签名称
/// - `file_name`: 要下载的附件文件名
///
/// # 返回值
/// 成功时返回文件数据流，失败时返回错误
pub async fn download_asset(or: &str, tag: &str, file_name: &str) -> anyhow::Result<()> {
    let url = format!(
        "{}/repos/{}/releases/{}/attach_files/{}/download",
        Host, or, tag, file_name
    );

    let response = CLIENT
        .get(&url)
        .headers({
            let mut headers = HEADERS.clone(); // 新建HeaderMap
            headers.insert(reqwest::header::ACCEPT, "application/json".parse().unwrap());
            headers
        })
        .send()
        .await
        .context("Failed to send request to GitCode API")?;

    // 先获取响应文本
    let response_text = response
        .text()
        .await
        .context("Failed to get response text")?;

    println!("{:?}", response_text);

    Ok(())
    // ...
}

/// 获取并处理上传URL
pub async fn upload(upload: UploadUrlResponse, file_data: Vec<u8>) -> anyhow::Result<()> {
    let mut headers = HEADERS.clone();
    headers.insert(
        "x-obs-meta-project-id",
        upload.headers.x_obs_meta_project_id.parse()?,
    );
    headers.insert("x-obs-acl", upload.headers.x_obs_acl.parse()?);
    headers.insert("x-obs-callback", upload.headers.x_obs_callback.parse()?);
    headers.insert("Content-Type", upload.headers.content_type.parse()?);

    println!("准备上传文件到: {}", upload.url);
    println!("请求头: {:?}", headers);
    println!("文件大小: {} 字节", file_data.len());

    let response = CLIENT
        .put(&upload.url)
        .headers(headers)
        .body(file_data)
        .send()
        .await?;

    let status = response.status();
    let response_text = response.text().await?;

    println!("响应状态: {}", status);
    println!("响应内容: {}", response_text);

    if !status.is_success() {
        return Err(anyhow::anyhow!("上传失败: {}", response_text));
    }

    println!("上传成功，服务器响应: {}", response_text);
    Ok(())
}

// fn parse_response(response_text: String) -> anyhow::Result<Result<ReleaseResponse, ApiError>> {
//     serde_json::from_str::<ReleaseResponse>(&response_text)
//         .map(Ok)
//         .or_else(|_| serde_json::from_str::<ApiError>(&response_text).map(Err))
//         .map_err(|e| anyhow::anyhow!("响应解析失败: {}\n原始响应: {}", e, response_text))
// }

// 修改parse_response函数使用宏
fn parse_response(response_text: String) -> anyhow::Result<Result<ReleaseResponse, ApiError>> {
    parse_json!(&response_text, ReleaseResponse)
        .map(Ok)
        .or_else(|_| parse_json!(&response_text, ApiError).map(Err))
}

#[cfg(test)]
mod tests {
    use super::*;
    const OR: &str = "loyoi/font-correct-data";

    #[tokio::test] // 添加 tokio 测试宏
    async fn test_create_release() {
        match create_release(OR, "v1.0", "v0.0.1", "你是大帅哥111", None).await {
            Ok(release) => match release {
                Ok(data) => println!(" {:?}", data),
                Err(err) => println!("{:?}", err),
            },
            Err(e) => println!("系统错误: {}", e), // 只打印错误信息，不打印堆栈
        }
    }

    #[tokio::test] // 添加 tokio 测试宏
    async fn test_update_release() {
        match update_release(OR, "v1.0", "v0.0.1", "你是大帅哥111").await {
            Ok(release) => match release {
                Ok(data) => println!(" {:?}", data),
                Err(err) => println!("{:?}", err),
            },
            Err(e) => println!("系统错误: {}", e), // 只打印错误信息，不打印堆栈
        }
    }

    #[tokio::test] // 添加 tokio 测试宏
    async fn test_fetch_upload_url() {
        match fetch_upload_url(OR, "v1.0", "data.json").await {
            Ok(release) => match release {
                Ok(data) => {
                    println!("{:?}", data);
                    let json_data = json!({
                        "key1": "value1",
                        "key2": 123,
                        "key3": ["item1", "item2"]
                    });
                    let bytes = serde_json::to_vec(&json_data).unwrap();
                    upload(data, bytes).await.unwrap();
                    println!("上传成功");
                }
                Err(err) => println!("{:?}", err),
            },
            Err(e) => println!("系统错误: {}", e), // 只打印错误信息，不打印堆栈
        }
    }
}
